//【习10.1】 基于Socket通信的裁判评分。
//裁判长程序。使用表格模型，动态增加表格模型的列与行。 
package org.langqiao.network.judge;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;                //默认表格模型
import java.io.*;
import java.net.*;

public class UmpireInChiefJFrame extends JFrame implements ActionListener
{
    private JTextField text_player;                        //输入选手名的文本行
    private JButton buttons[];                             //按钮数组
    private DefaultTableModel tableModel;                  //默认表格模型
    private int row=-1;                                    //tableModel的当前行序号(>=0)
    private SocketThread socketThreads[];                  //基于Socket连接的线程数组，内部类对象
    private int port;                                      //多条Socket连接的起始端口
    private int count;                                     //裁判人数
    private Average av;                                    //提供求平均值的方法，Average接口声明见习4.2

    public UmpireInChiefJFrame(int port, int count, Average av) throws Exception 
    {                            //port指定Socket连接的起始端口，count指定裁判人数，av提供求平均值的方法
        super("裁判长");
        this.setBounds(240,200,400,400);
        this.setBackground(Color.lightGray);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.tableModel=new DefaultTableModel();           //默认表格模型，没有列标题，0行
        this.getContentPane().add(new JScrollPane(new JTable(tableModel)));
        this.tableModel.addColumn("参赛选手/裁判");         //表格模型添加列，参数指定列名
        
        JPanel panel = new JPanel();
        this.getContentPane().add(panel,"South");
        panel.add(new JLabel("选手名"));
        text_player = new JTextField("",10);
        panel.add(text_player);
        String bstr[]={"发送","计算得分","结束"};        
        buttons=new JButton[bstr.length];
        for(int i=0; i<buttons.length; i++)
        {
            buttons[i]=new JButton(bstr[i]);
            panel.add(buttons[i]);
            buttons[i].addActionListener(this); 
        }
        buttons[1].setEnabled(false);
        this.setVisible(true);

        this.port = port;
        this.count = count;
        this.socketThreads=new SocketThread[count];
        for (int i=0; i<count; i++)
            this.socketThreads[i] = new SocketThread(i);  //创建内部类对象
        this.tableModel.addColumn("选手得分");
        this.av=av;
    }

    private class SocketThread extends Thread              //内部类，创建并启动线程，在约定端口等待接收客户端的连接申请 
    {
        Socket socket;                                     //一条TCP连接的一端
        PrintWriter pout;                                  //格式化字符输出流
        DataInputStream din;                               //数据字节输入流
        int number;                                        //为客户端约定的序号
        
        SocketThread(int number) throws IOException
        {
            this.number = number;
            socket = new ServerSocket(port+number).accept();//在约定端口等待接收客户端的连接申请
            BufferedReader cin=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                                                           //由Socket输入流创建字符输入流
            tableModel.addColumn(cin.readLine());      //表格模型添加列，列名是读取的裁判名
            pout=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true); //由Socket输出流字符输出流，立即传输
            din = new DataInputStream(socket.getInputStream());  //由Socket输入流创建数据字节输入流
            this.start();                                  //启动线程
        }
        public void run() 
        {
            try
            {
                while (true)
                    try
                    {                                      //将读取的数值显示在表格当前行相应裁判名下
                        tableModel.setValueAt(""+din.readDouble(), row, number+1); 
                        buttons[1].setEnabled(true);
                    }
                    catch (Exception e)                    //数据字节输入流结束
                    {
                        break;
                    }
                    din.close();                           //关闭数据流
                    socket.close();                        //关闭Socket连接
            }
            catch(IOException e)
            {
//                e.printStackTrace();
            }
        }
    }
    
    public void actionPerformed(ActionEvent e)             //单击事件处理方法
    {
        if (e.getSource()==buttons[0])                     //"发送"按钮
        {
            String name=text_player.getText();             //选手名
            if (name.equals(""))
            {
                JOptionPane.showMessageDialog(this,"请输入选手名!");
                return;
            }
            Object objs[]=new Object[count+2];
            this.tableModel.addRow(objs);                  //表格模型添加行
            row++;                                         //表格模型当前行
            this.tableModel.setValueAt(name, row, 0);      //表格当前行第0列设置为选手名
            buttons[0].setEnabled(false);
            for (int i=0; i<count; i++)                    //发送选手名给所有客户端
                this.socketThreads[i].pout.println(name);
            return;
        }

        if (e.getSource()==buttons[1])                     //"计算得分"按钮
        {
            double value[]=new double[count];
            for (int i=0; i<count; i++)
                value[i]=Double.parseDouble((String)this.tableModel.getValueAt(row, i+1));
            this.tableModel.setValueAt(""+av.average(value), row, count+1); //表格当前行最后列设置为平均值
            text_player.setText("");
            buttons[0].setEnabled(true);
            buttons[1].setEnabled(false);
            return;
        }
        if (e.getSource()==buttons[2])                     //"结束"按钮
        {
            for (int i=0; i<count; i++)                    //关闭所有线程的输出流，导致结束所有客户端的输入流
        	    this.socketThreads[i].pout.close();
            for (int i=0; i<3; i++)                        //己方按钮无效
                buttons[i].setEnabled(false);
        }
    }

    public static void main(String arg[]) throws Exception
    {
        new UmpireInChiefJFrame(2010, 2, new AverageAll());
    }
}
